#include "private_implementations/JsonObjectNode.h"
#include "private_implementations/JsonUtil.h"
#include <sstream>
#include <vector>
#include <iosfwd>

simframework::json::JsonObjectNode::JsonObjectNode(SimWString str)
{
	size_t s = str.find_first_of(L"{") + 1;
	size_t e = str.find_last_of(L"}");

	m_valueStr = str.substr(s, e-s);
	m_startIt = m_valueStr.begin();
	m_endIt = m_valueStr.end();
}

simframework::json::JsonAbstractNode* simframework::json::JsonObjectNode::getValue(simframework::json::JSONType type, SimWString name, int* status)
{
	for (; m_startIt != m_endIt; ++m_startIt)
	{
		SimWString key = JSONUtil::getKey(m_startIt, m_endIt);
		if (key.compare(name) == 0)
		{
			JSONUtil::removeSpaces(m_startIt, m_endIt);
			if (*m_startIt != ':')
			{
				if (status) *status = JSON_FAIL;
				return JSONUtil::getDefault(type);
			}
			m_startIt++; // skip :
			JSONUtil::removeSpaces(m_startIt, m_endIt);

			if (JSONUtil::checkForNull(m_startIt, m_endIt))
			{
				if (status) *status = JSON_NULL;
				JSONUtil::cleanUp(m_startIt, m_endIt);
				return JSONUtil::getDefault(type);
			}

			JsonAbstractNode * data = NULL;
			switch (type)
			{
			case JSON_OBJECT:
				data = JSONUtil::getObjectValue(m_startIt, m_endIt, status);
				break;
			case JSON_ARRAY:
				data = JSONUtil::getArrayValue(m_startIt, m_endIt, status);
				break;
			case JSON_STRING:
				data = JSONUtil::getStringValue(m_startIt, m_endIt, status);
				break;
			case JSON_FLOAT:
				data = JSONUtil::getFloatValue(m_startIt, m_endIt, status);
				break;
			case JSON_INTEGER:
				data = JSONUtil::getIntValue(m_startIt, m_endIt, status);
				break;
			case JSON_BOOLEAN:
				data = JSONUtil::getBooleanValue(m_startIt, m_endIt, status);
				break;
			default:
				if (status) *status = JSON_FAIL;
				break;
			}
			JSONUtil::cleanUp(m_startIt, m_endIt);
			return data;
		}
		else
		{
			JSONUtil::skipValue(m_startIt, m_endIt);
		}
		JSONUtil::cleanUp(m_startIt, m_endIt);

		if (m_startIt == m_endIt) break;
	}

	if (status) *status = JSON_FAIL;
	return JSONUtil::getDefault(type);
}

simframework::json::JsonObjectNode * simframework::json::JsonObjectNode::getObjectValueByKey(SimWString name, int* status)
{
	return static_cast<JsonObjectNode*>(getValue(JSON_OBJECT, name, status));
}

simframework::json::JsonArrayNode * simframework::json::JsonObjectNode::getArrayValueByKey(SimWString name, int* status)
{
	return static_cast<JsonArrayNode*>(getValue(JSON_ARRAY, name, status));
}

SimWString simframework::json::JsonObjectNode::getStringValueByKey(SimWString name, int* status)
{
	int err;
	JSONString* data = static_cast<JSONString*>(getValue(JSON_STRING, name, &err));
	if (data)
	{
		if (err == JSON_SUCCESS)
		{
			if (status) *status = err;
			SimWString ws = data->strValue;
			delete data;
			return ws;
		}
		else if(err == JSON_NULL)
		{
			if (status) *status = err;
			return L"";
		}
	}
	if (status) *status = JSON_FAIL;
	return L"";
}

double simframework::json::JsonObjectNode::getFloatValueByKey(SimWString name, int* status)
{
	int err;
	JSONFloat* data = static_cast<JSONFloat*>(getValue(JSON_FLOAT, name, &err));
	if (data)
	{
		if (err == JSON_SUCCESS)
		{
			if (status) *status = err;
			double d = data->fValue;
			delete data;
			return d;
		}
		else if(err == JSON_NULL)
		{
			if (status) *status = err;
			return -1;
		}
	}
	if (status) *status = JSON_FAIL;
	return -1;
}

int simframework::json::JsonObjectNode::getIntValueByKey(SimWString name, int* status)
{
	int err;
	JSONInteger* data = static_cast<JSONInteger*>(getValue(JSON_INTEGER, name, &err));
	if (data)
	{
		if (err == JSON_SUCCESS)
		{
			if (status) *status = err;
			int d = data->iValue;
			delete data;
			return d;
		}
		else if(err == JSON_NULL)
		{
			if (status) *status = err;
			return -1;
		}
	}
	if (status) *status = JSON_FAIL;
	return -1;
}

bool simframework::json::JsonObjectNode::getBooleanValueByKey(SimWString name, int* status)
{
	int err;
	JSONBoolean* data = static_cast<JSONBoolean*>(getValue(JSON_BOOLEAN, name, &err));
	if (data)
	{
		if (err == JSON_SUCCESS)
		{
			if (status) *status = err;
			bool b = data->bValue;
			delete data;
			return b;
		}
		else if(err == JSON_NULL)
		{
			if (status) *status = err;
			return false;
		}
	}
	if (status) *status = JSON_FAIL;
	return false;
}